Effective C++ 条款30 inline

条款30 : 透彻了解inlining的里里外外

inline 函数, 多么棒的点子! 本条款将带我们透彻了解inlining的里里外外, 与往常的形式不同, 我会以知识点集的形式把书中对inline的描述列举处理, 可更简单明了的认识inline.

inline的优劣

  • inline函数, 看起来像函数, 动作像函数, 却比宏好得多, 调用它们不用蒙受函数调用所带来的额外开销.
  • 编译器会对inline函数执行语境相关最优化, 会提升编译效率.
  • 如果内存有限, 过度inlining会造成程序体积太大.
  • inline会带来代码膨胀, 进而导致额外的换页行为, 降低高速缓存装置的击中率.
  • 如果inline函数的本体很小, 编译器针对”函数本体”产出的码可能比针对”函数调用”产出的码更小, 反而会促成与上一条相反的情况, 可以导致较小的目标码和较高的高速缓存装置击中率.
  • inline函数无法随程序库的升级而升级, 简单说如果程序库中有一个inline函数, 如果决定改变该函数, 那么程序库中所有用到该函数的程序就必须重新编译. 如果是non-inline函数,客户端只需要重新连接就好了, 没有那么大的编译负担, 如果是动态库就更没有了.

inline的特性

  • inline不是一个强制命令, 它只是对编译器的一个申请! 编译器可以加以忽略, 大部分编译器将拒绝太过复杂的函数(含循环, 递归, 长度过长)进行inlining. 简而言之, 一个表面看似inline的函数是否真的是inline, 取决于你的建置环境, 主要取决于编译器.

  • inline可以明确提出, 也可以隐喻提出.

  • 隐喻提出的方式是将函数定义在class定义式中. 这便是为什么很多class会将实现简短的函数直接在class定义式中将声明定义一并给出, 其实就是在方便的前提下还隐喻地使用了inline函数, 以达到”没有声明任何inline却处处都是inline“的效果.

  • 隐喻inline函数通常是成员函数, 也可以是friend函数.

  • 所有virtual函数与调用virtual的函数都无法inlining. virtual代表着等待运行时判定, 而inline代表编译时提前替换, 这两种行为是绝对冲突的.


inline的使用

  • inline函数通常一定被置于头文件内, 因为大多数建置环境都在编译过程中进行inline.
  • templates(泛型类/函数)通常也被置于头文件内, 很多程序员认为泛型函数一定都是inline, 但这是错误的, template的实例化与inline无关, 不应该这样考量, 还是应该依照代码长度,内容以及环境做具体考量.
  • 构造函数和析构函数往往是inlining的糟糕候选人, 因为就算它们是空白的, 也有可能在底层被编译器施加很多额外的代码, 例如基类的构造与析构, 这导致它们的实际代码量远比我们看见的要多得多, 令它们inlining很有可能会发生代码膨胀.
  • 一开始先不要将任何函数声明成inline, 除非你非常笃定它就是inline的典型案例, 当你开始关心效率时, 再分析是否可以inlining.

请记住 :

  • 请将大多数的inlining限制在小型, 被频繁调用的函数身上.
  • 通过将函数定义在class定义式中实现隐喻inline.

by 天目中云


Effective C++ 条款30 inline
http://example.com/2024/12/09/[Effective C++]条款30 inline/
作者
天目中云
发布于
2024年12月9日
许可协议